#ifndef HSL_HEURISTIC_H
#define HSL_HEURISTIC_H

#include "Config.h"
#include "None.h"

/// To keep the code size minimal, 
/// the non-template part of the Heuristic
/// class is kept in this class. TODO: add reference
class HeuristicNonTemplate {
public:
	void preExecute() {
	}
	void postExecute() {
	}

    /// print function to be implemented by derived classes
 //   virtual void print(std::ostream& os) = 0; 
};

// The Heuristic class needs a variable number of template 
// arguments. This is implemented in a typical way that uses
// partial template specialization. For a simple example
// of this technique, see http://goo.gl/F3Zw7
// 
// FUTURE (C++0x): Can use variadic templates for a simpler 
// implementation.

template <typename Derived, typename T, typename F1 = None, 
          typename F2 = None, typename F3 = None>
class Heuristic;

/// The base class of heuristics with zero input features.
///
/// A Heuristic with:
/// - Target class T
template<typename Derived, typename T> 
class Heuristic<Derived, T>: public HeuristicNonTemplate
{
public:
	/// The apply() function is called by a Run to execute the Heuristic.
	/// The execute() function below must be implemented by a derived class. 
    ///    public: T execute() const;
	T apply() {
		preExecute();
		T t = static_cast<Derived*>(this)->execute();
		postExecute();
		return t;
	}
    
};

/// The base class of heuristics with one input feature.
///
/// A Heuristic with:
/// - Target class T, 
/// - Input Feature class F1
template<typename Derived, typename T, typename F1> 
class Heuristic<Derived, T, F1>: public HeuristicNonTemplate
{
public:
	/// The apply() function is called by a Run to execute the Heuristic.
	/// The execute() function below must be implemented by a derived class. 
    ///    public: T execute(F1 feature) const;
	T apply(F1 feature1) {
		preExecute();
		T t = static_cast<Derived*>(this)->execute(feature1);
		postExecute();
		return t;
	}
};

/// The base class of heuristics with two input features.
///
/// A Heuristic with:
/// - Target class T, 
/// - Input Feature classes F1 and F2
template<typename Derived, typename T, typename F1, typename F2> 
class Heuristic<Derived, T, F1, F2>: public HeuristicNonTemplate
{
public:
    /// The apply() function is called by a Run to execute the Heuristic.
	/// The execute() function below must be implemented by a derived class. 
    ///    public: T execute(F1 feature1, F2 feature2) const;
	T apply(F1 feature1, F2 feature2) {
		preExecute();
		T t = static_cast<Derived*>(this)->execute(feature1, feature2);
		postExecute();
		return t;
	}
};

#endif
